package dbAccess;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;



/**
 * This class takes in parameter for database connection and the path and creates all the 
 * data access layer freeing up programmers like me from doing that.
 * This has been written specifically to mysql database
 * @author Sandeep.Dhankar
 *
 */

public class Controller {

	
	 private static String path="data";
	 private static String domainPath=path+"/beans";
	 private static String indPath=path+"/beanIndicators";
	 private static String controllerpath=path+"/dao";
	 private static String configPath=path+"/config";
	 
	 private static String driver="com.mysql.jdbc.Driver";
	 private static String username="root";
	 private static String password="";
	 private static String url="jdbc:mysql://localhost/kollege";
	 
		  public static void main(String args[]) {
		    String url = Controller.url;
		 
		    
		    
		    try {
		      Class.forName(Controller.driver);
		    }
		    catch( Exception e ) {
		      System.out.println("Failed to load mSQL driver.");
		      return;
		    }
		    try {
		      Connection con = DriverManager.getConnection(url, Controller.username, Controller.password);
		      List<String> tableNames=new ArrayList<String>();
		      
		      
		      
		      //Get the table names
		      Statement select = con.createStatement();
		      ResultSet result = select.executeQuery("Show tables");         
		      
		      while(result.next()) { // process results one row at a time
		    	 
		    	  tableNames.add(result.getString(1));
		      }
		      select.close();
		      
		      if(tableNames.size()>0){
		    	  File dir = new File("src/"+indPath);
				  if(!dir.exists()){
					  dir.mkdirs();
				  }
				  dir = new File("src/"+domainPath);
				  if(!dir.exists()){
					  dir.mkdirs();
				  }
				  
				  dir = new File("src/"+controllerpath);
				  if(!dir.exists()){
					  dir.mkdirs();
				  }
				  dir = new File("src/"+configPath);
				  if(!dir.exists()){
					  dir.mkdirs();
				  }
				  //This method creates the config class for database access
				  createConfigClass();
				  
				  
		      }
		      
		      for(int counter=0;counter<tableNames.size();counter++){
		    	  
		    	  
		    	  select = con.createStatement();
		    	  result= select.executeQuery("Describe "+tableNames.get(counter));
		    	  createClasses(result,tableNames.get(counter).toUpperCase().charAt(0)+tableNames.get(counter).substring(1));
		    	  select.close();
		    	  
		    	  
		      }
		            
		      
		      con.close();
		    }
		    catch( Exception e ) {
		      e.printStackTrace();
		    }
		  }
		  
		  
		  /**
		   * This method creates a class to hold database configuration properties for connection
		 * @throws UnsupportedEncodingException 
		 * @throws FileNotFoundException 
		   */
		  private static void createConfigClass() throws FileNotFoundException, UnsupportedEncodingException {
			  PrintWriter config = new PrintWriter("src/"+configPath+"/DbAccessConfigFactory.java", "UTF-8");
			  
			  config.println("package "+configPath.replaceAll("/", ".")+";");
			  config.println();
			  
			  config.println("import dbAccess.DbAccessSessionFactory;");

	    	  config.println("public class DbAccessConfigFactory {");
	    	  config.println();
	    	  config.println("   // This file is created automatically by DbAccessController, you can modify the parameters to use with multiple databases");
			  config.println("   private static DbAccessSessionFactory dbAccessSessionFactory=null;");
			  config.println();
			  config.println("	 static{");
			  config.println("	     dbAccessSessionFactory =new DbAccessSessionFactory(\""+Controller.driver+"\",\""+Controller.username+"\",\""+Controller.password+"\",\""+Controller.url+"\");");
			  config.println("   }");
			  config.println();
			  config.println("   public static DbAccessSessionFactory getSqlSessionFactory() {");
			  config.println("        return dbAccessSessionFactory;");
			  config.println("	 }");
			  config.println(" }");		  
			  config.close();
			
		}



		/**
		   * This class creates the necessary classes required for data access
		   * @param result
		   * @param className
		   * @throws Exception
		   */
		  public static void createClasses(ResultSet result, String className) throws Exception{
			 
			  
			
			  
			  //create the bean class
			  PrintWriter bean = new PrintWriter("src/"+domainPath+"/"+className+".java", "UTF-8");
			  
			  bean.println("package "+domainPath.replaceAll("/", ".")+";");
			  bean.println();
			  			  
			  bean.println("import java.util.ArrayList;");
			  bean.println("import java.util.Date;");
			  bean.println("import java.util.List;");
			  bean.println("import dbAccess.DbAccessConstants;");
			  bean.println("import dbAccess.DbProperty;");
			  bean.println("import dbAccess.IDbAccessObject;");
			  
			  bean.println();
			  bean.println();
			  
			  bean.println("//This is file is generated automatically by dbAccess");
			  bean.println();
			  bean.println();
			  bean.println("public class "+ className+" implements IDbAccessObject{");
			  
			  
			  //create the indicator class
			  
			  PrintWriter indicator = new PrintWriter("src/"+indPath+"/"+className+"Indicator.java", "UTF-8");
			  
			  indicator.println("package "+indPath.replaceAll("/", ".")+";");
			  indicator.println();
			  
			  indicator.println("import java.util.ArrayList;");
			  indicator.println("import java.util.List;");
			  indicator.println();
			  indicator.println();
			  indicator.println("//This is file is generated automatically by dbAccess");
			  indicator.println();
			  indicator.println();
			  indicator.println("public class "+ className+"Indicator  {");
			  
			  
			  
			  
			  String variable=null;
			  String dataType=null;
			  String value="null";
			  List<Property> vars =new ArrayList<Property>();
			  Property prop=null;
			  
			   while(result.next()) {
				 
				  
				   
				   
				   value="null";
				   dataType=null;
				   
				   	if(("auto_increment").equalsIgnoreCase(result.getString(6))){
				   		prop= new Property();
						   prop.setPropertyName("autoIncrementKey");
						   prop.setDataType("long");
						   prop.setValue("DbAccessConstants.DB_ACCESS_INVALID");
						   vars.add(prop);
				   		
				   	}
				   
				  if(result.getString(2).matches("(.*)blob(.*)|(.*)text(.*)|(.*)char(.*)")){
					  dataType ="String";
					  value="null";
					  
				  }
				  else if(result.getString(2).matches("(.*)int(.*)|number")){
					  dataType ="int";
					  value="DbAccessConstants.DB_ACCESS_INVALID";
				  }
				  
				  else if(result.getString(2).matches("decimal|float")){
					  dataType ="float";
					  value="DbAccessConstants.DB_ACCESS_INVALID";
				  }
				  else if(result.getString(2).matches("double")){
					  dataType ="double";
					  value="DbAccessConstants.DB_ACCESS_INVALID";
				  }
				  else if(result.getString(2).matches("date|timestamp")){
					  dataType ="Date";
					  value="null";
				  }
				  
				 
				  variable =result.getString(1);
				  prop= new Property();
				   prop.setPropertyName(variable);
				   prop.setDataType(dataType);
				   prop.setValue(value);
				  
				 
				   vars.add(prop);
			               				  
	    		  
	    	  }
			   
			   
			   
			   
			   createBeanClass(bean,vars,className);
			   bean.println("}");
			   bean.close();
			   
			   createIndicatorClass(indicator,vars);
			   
			   indicator.println("}");
			   indicator.close();
			   
			   createControllerClass(className);
			   
			   
			  
		  }
		  
		/**
		 * This is the bean which is key to our whole effort of avoiding reflection  
		 * @param bean
		 * @param vars
		 */
		  
		private static void createBeanClass(PrintWriter bean,List<Property> vars, String className) {
			
			
			
			//constructor
			StringBuffer str=new StringBuffer();
			for (Property prop:vars) {
				str.append(", ").append(prop.getDataType()).append(" ").append(prop.getPropertyName());
			}
			
			bean.println("   public void setObject(List<DbProperty> properties){");
			bean.println("        for(DbProperty dbProp:properties){");
			String elseStr="";
			for (Property prop:vars) {
				
				bean.println("          "+elseStr+" if(dbProp.getPropertyName().equalsIgnoreCase(\""+prop.getPropertyName()+"\".intern())){");
													
				bean.println("            this."+prop.getPropertyName()+" = ("+getProperCast(prop.getDataType())+") dbProp.getValue();  ");
				bean.println("         }");
				elseStr="else";
			}
			bean.println("        }");
			bean.println("     }");
			
			bean.println("");
			bean.println("      public List<DbProperty> getInput(){");
			bean.println("          List<DbProperty> list= new ArrayList<DbProperty>();");
			
		
			for (Property prop:vars) {
			   bean.println("          if(this."+prop.getPropertyName()+"!= "+prop.getValue() +"){");			   		  
			   bean.println("            list.add(new DbProperty(\""+prop.getPropertyName()+"\",this."+prop.getPropertyName()+"));");	
				bean.println("           }");
			}			
			bean.println("             return list;         ");
			bean.println("         }");
			
			//properties
			for (Property prop:vars) {
			      
				bean.println("     private "+prop.getDataType() +" "+prop.getPropertyName()+" = "+prop.getValue() +" ;");	     
			      
			    }
			    
			bean.println();
			
			
			//getter method
			for (Property prop:vars) {
			      
				  //set the getter method
				  bean.println("     public "+prop.getDataType()+ " get"+prop.getPropertyName().toUpperCase().charAt(0)+prop.getPropertyName().substring(1)+"(){");
				  bean.println("            return this."+prop.getPropertyName()+";");
				  bean.println("     }");
				  bean.println();	     
			      
			    }
			    
			bean.println();
			
			//setter method
			for (Property prop:vars) {
			      
				 //set the setter method
				  bean.println("     public void set"+prop.getPropertyName().toUpperCase().charAt(0)+prop.getPropertyName().substring(1)+"("+prop.getDataType()+" value){");
				  bean.println("              this."+prop.getPropertyName()+"  =value;");
				  bean.println("     }");
				  bean.println(); 	     
			      
			    }
			    
			bean.println();
			
		}



		private static String getProperCast(String dataType) {
			if(dataType==null){
				return dataType;
			}
			
			if(dataType.equalsIgnoreCase("int")){
				return "Integer";
			}
			else if(dataType.equalsIgnoreCase("long")){
				return "Long";
			}
			return dataType;
		}


		/**
		 * This method creates the indicator class  
		 * @param indicator
		 * @param vars
		 */
		private static void createIndicatorClass(PrintWriter writer,	List<Property> vars) {
			
			for (Property propertyName:vars) {
			     if(!propertyName.getPropertyName().equalsIgnoreCase("autoIncrementKey")){ 
			      writer.println("     private boolean "+propertyName.getPropertyName()+"Ind=true;");	
			     }
			      
			    }
			    
			    writer.println();
			
			for (Property propertyName:vars) {
			      
				if(!propertyName.getPropertyName().equalsIgnoreCase("autoIncrementKey")){  
			           writer.println("     public boolean is"+propertyName.getPropertyName().toUpperCase().charAt(0)+propertyName.getPropertyName().substring(1)+"Ind(){");
			        writer.println("            return this."+propertyName.getPropertyName()+"Ind;");
			        writer.println("     }");
			        writer.println();
				}       
			      }
			    
			    
			 for (Property propertyName:vars) {
				 if(!propertyName.getPropertyName().equalsIgnoreCase("autoIncrementKey")){ 
			              writer.println("     public void set"+propertyName.getPropertyName().toUpperCase().charAt(0)+propertyName.getPropertyName().substring(1)+"Ind(boolean value){");
			        writer.println("              this."+propertyName.getPropertyName()+"Ind =value;");
			        writer.println("     }");
			        writer.println(); 
				 } 
			        }
			      
			    
			    writer.println("     public  List<String> getObject(){");
			    writer.println("            List<String> result =new ArrayList<String>();");
			    
			    for (Property propertyName:vars) {
			    	if(!propertyName.getPropertyName().equalsIgnoreCase("autoIncrementKey")){ 
			    	    writer.println("              if(this."+propertyName.getPropertyName()+"Ind){");
			        	writer.println("                   result.add(\""+propertyName.getPropertyName()+"\");");
			        	writer.println("               }"); 
			    	}
			      
			    }
			    			    
			    writer.println("             return result;");
			    writer.println("      }"); 
			
		}



		/**
		 * This method creates a controller to access database requests
		 * @param className
		 * @throws FileNotFoundException
		 * @throws UnsupportedEncodingException
		 */
		private static void createControllerClass(String className) throws FileNotFoundException, UnsupportedEncodingException {
			 
			String beanClass=className;
			String indicatorClass=className+"Indicator";
			String classVariable=className.toLowerCase().charAt(0)+className.substring(1);
			String indicatorVariable=className.toLowerCase().charAt(0)+className.substring(1)+"Indicator";
			
			 PrintWriter dao = new PrintWriter("src/"+controllerpath+"/"+className+"Dao.java", "UTF-8");
			  
			 dao.println("package "+controllerpath.replaceAll("/", ".")+";");
			 dao.println();
			 dao.println("import "+domainPath.replaceAll("/", ".")+"."+className+";");
			 dao.println("import "+indPath.replaceAll("/", ".")+"."+className+"Indicator;");
			 dao.println("import java.util.List;");
			 dao.println("import dbAccess.SelectClauseBounds;");
			 dao.println();
			 dao.println();
			 dao.println("//This is file is generated automatically by dbAccess");
			 dao.println();
			 dao.println();
			 dao.println("public interface "+ className+"Dao {");
			 dao.println();
			 dao.println();
			 dao.println("         public void update"+className+"("+beanClass+" "+classVariable+") throws Exception;");
			 dao.println("         public void updateSelected"+className+"("+beanClass+" "+classVariable+"Input, "+beanClass+" "+classVariable+"Condition) throws Exception;");
			 dao.println("         public void delete"+className+"("+beanClass+" "+classVariable+") throws Exception;");
			 dao.println("         public void insert"+className+"("+beanClass+" "+classVariable+") throws Exception;");
			
			 dao.println("         public "+beanClass+" selectOne"+className+"("+beanClass+" "+classVariable+") throws Exception;");
			 dao.println("         public List<"+beanClass+"> selectList"+className+"("+beanClass+" "+classVariable+") throws Exception;");
			 dao.println("         public "+beanClass+" selectOne"+className+"("+indicatorClass+" "+indicatorVariable +", "+beanClass+" "+classVariable+"Condition , SelectClauseBounds bounds) throws Exception;");
			 dao.println("         public List<"+beanClass+"> selectList"+className+"("+indicatorClass+" "+indicatorVariable +","+beanClass+" "+classVariable+"Condition , SelectClauseBounds bounds) throws Exception;");

			 
			  
			 dao.println("}");
			 dao.close();
			
			
			PrintWriter daoImpl = new PrintWriter("src/"+controllerpath+"/"+className+"DaoImpl.java", "UTF-8");
			  
			 daoImpl.println("package "+controllerpath.replaceAll("/", ".")+";");
			 daoImpl.println();
			 daoImpl.println();
			 daoImpl.println("import "+domainPath.replaceAll("/", ".")+"."+className+";");
			 daoImpl.println("import "+indPath.replaceAll("/", ".")+"."+className+"Indicator;");
			 
			 daoImpl.println("import java.util.logging.Level;");
			 daoImpl.println("import java.util.logging.Logger;");
			 daoImpl.println("import java.util.List;");			 
			 daoImpl.println("import data.config.DbAccessConfigFactory;");
			 daoImpl.println("import dbAccess.DbAccessSession;");
			 daoImpl.println("import dbAccess.DbAccessSessionFactory;");
			 daoImpl.println("import dbAccess.SelectClauseBounds;");
			 daoImpl.println();
			 daoImpl.println();
			 daoImpl.println("//This is file is generated automatically by dbAccess");
			 daoImpl.println();
			 daoImpl.println();
			 daoImpl.println("     public class "+ className+"DaoImpl  implements "+className+"Dao {");
			 daoImpl.println();
			 daoImpl.println();
			 daoImpl.println();
			 daoImpl.println("      private static Logger logger = Logger.getLogger("+className+"DaoImpl.class.getName());");
			 daoImpl.println("      private static String TABLE_NAME = \""+className+"\";");
			 
			 
			 daoImpl.println("      private DbAccessSessionFactory dbAccessSessionFactory =null;");
			 
			 daoImpl.println();
			 daoImpl.println("       public "+className+"DaoImpl(){");
			 daoImpl.println("           dbAccessSessionFactory= DbAccessConfigFactory.getSqlSessionFactory();");
			 daoImpl.println("           logger.log(Level.INFO,\"Session Factory instantiated sucessfully\");");
			 daoImpl.println("        }");
			 daoImpl.println();
			 daoImpl.println();
			 daoImpl.println("         @Override");
			 daoImpl.println("         public void update"+className+"("+beanClass+" "+classVariable+") throws Exception {");
			 daoImpl.println("              DbAccessSession session= dbAccessSessionFactory.getDbAccessSession();");
			 daoImpl.println("               session.openDbSession();");
			 daoImpl.println();
			 daoImpl.println("               try{");
			 daoImpl.println("              	session.update(TABLE_NAME, "+classVariable+");");
			 daoImpl.println();	
			 daoImpl.println("                }");
			 daoImpl.println("                finally{");
			 daoImpl.println("              	session.closeDbSession();");
			 daoImpl.println("              }");
			 daoImpl.println("         }");
			 
			 
			 daoImpl.println();
			 daoImpl.println();
			 daoImpl.println("         @Override");
			 daoImpl.println("         public void updateSelected"+className+"("+beanClass+" "+classVariable+"Input, "+beanClass+" "+classVariable+"Condition) throws Exception {");
			
			 daoImpl.println("              DbAccessSession session= dbAccessSessionFactory.getDbAccessSession();");
			 daoImpl.println("               session.openDbSession();");
			 daoImpl.println();
			 daoImpl.println("               try{");
			 daoImpl.println("              	session.update(TABLE_NAME, "+classVariable+"Input,"+classVariable+"Condition);");
			 daoImpl.println();	
			 daoImpl.println("                }");
			 daoImpl.println("                finally{");
			 daoImpl.println("              	session.closeDbSession();");
			 daoImpl.println("              }");
			 
			 daoImpl.println("         }");
			 
			 daoImpl.println();
			 daoImpl.println();
			 daoImpl.println("         @Override");
			 daoImpl.println("         public void delete"+className+"("+beanClass+" "+classVariable+") throws Exception {");
			
			 daoImpl.println("              DbAccessSession session= dbAccessSessionFactory.getDbAccessSession();");
			 daoImpl.println("               session.openDbSession();");
			 daoImpl.println();
			 daoImpl.println("               try{");
			 daoImpl.println("              	session.delete(TABLE_NAME, "+classVariable+");");
			 daoImpl.println();	
			 daoImpl.println("                }");
			 daoImpl.println("                finally{");
			 daoImpl.println("              	session.closeDbSession();");
			 daoImpl.println("              }");

			 daoImpl.println("         }");
			 daoImpl.println();
			 daoImpl.println();
			 daoImpl.println("         @Override");
			 daoImpl.println("         public void insert"+className+"("+beanClass+" "+classVariable+") throws Exception {");
			 
			 
			 daoImpl.println("              DbAccessSession session= dbAccessSessionFactory.getDbAccessSession();");
			 daoImpl.println("               session.openDbSession();");
			 daoImpl.println();
			 daoImpl.println("               try{");
			 daoImpl.println("              	session.insert(TABLE_NAME, "+classVariable+");");
			 daoImpl.println();	
			 daoImpl.println("                }");
			 daoImpl.println("                finally{");
			 daoImpl.println("              	session.closeDbSession();");
			 daoImpl.println("              }");

			 daoImpl.println("         }");
			 
			 daoImpl.println();
			 daoImpl.println();
			 daoImpl.println("         @Override");
			 daoImpl.println("         public "+beanClass+" selectOne"+className+"("+beanClass+" "+classVariable+") throws Exception {");
			
			 daoImpl.println("              DbAccessSession session= dbAccessSessionFactory.getDbAccessSession();");
			 daoImpl.println("               session.openDbSession();");
			 daoImpl.println();
			 daoImpl.println("               try{");
			 daoImpl.println("              	"+className+" result =("+className+") session.selectOne(\""+domainPath.replaceAll("/", ".")+"."+className+"\", TABLE_NAME, "+classVariable+");");
			 daoImpl.println("                    return result;");	
			 daoImpl.println();	
			 daoImpl.println("                }");
			 daoImpl.println("                finally{");
			 daoImpl.println("              	session.closeDbSession();");
			 daoImpl.println("              }");

			 daoImpl.println("         }");
			 daoImpl.println();
			 daoImpl.println();
			 daoImpl.println("         @Override");
			 daoImpl.println("         public List<"+beanClass+"> selectList"+className+"("+beanClass+" "+classVariable+") throws Exception {");
			
			 daoImpl.println("              DbAccessSession session= dbAccessSessionFactory.getDbAccessSession();");
			 daoImpl.println("               session.openDbSession();");
			 daoImpl.println();
			 daoImpl.println("               try{");
			 daoImpl.println("              	List<"+className+"> result = session.selectList(\""+domainPath.replaceAll("/", ".")+"."+className+"\", TABLE_NAME, "+classVariable+");");
			 daoImpl.println("                    return result;");	
			 daoImpl.println();	
			 daoImpl.println("                }");
			 daoImpl.println("                finally{");
			 daoImpl.println("              	session.closeDbSession();");
			 daoImpl.println("              }");
			 daoImpl.println("         }");
			 daoImpl.println();
			 daoImpl.println();
			 daoImpl.println("         @Override");
			 daoImpl.println("         public "+beanClass+" selectOne"+className+"("+indicatorClass+" "+indicatorVariable +", "+beanClass+" "+classVariable+"Condition , SelectClauseBounds bounds) throws Exception {");
			 
			 daoImpl.println("              DbAccessSession session= dbAccessSessionFactory.getDbAccessSession();");
			 daoImpl.println("               session.openDbSession();");
			 daoImpl.println();
			 daoImpl.println("               try{");
			 daoImpl.println("              	"+className+" result =("+className+") session.selectOne(\""+domainPath.replaceAll("/", ".")+"."+className+"\", TABLE_NAME, "+indicatorVariable+".getObject(),"+classVariable+"Condition ,bounds);");
			 daoImpl.println("                    return result;");	
			 daoImpl.println();	
			 daoImpl.println("                }");
			 daoImpl.println("                finally{");
			 daoImpl.println("              	session.closeDbSession();");
			 daoImpl.println("              }");
			 daoImpl.println("         }");
			 
			 daoImpl.println();
			 daoImpl.println();
			 daoImpl.println("         @Override");
			 daoImpl.println("         public List<"+beanClass+"> selectList"+className+"("+indicatorClass+" "+indicatorVariable +","+beanClass+" "+classVariable+"Condition , SelectClauseBounds bounds) throws Exception {");

			 daoImpl.println("              DbAccessSession session= dbAccessSessionFactory.getDbAccessSession();");
			 daoImpl.println("               session.openDbSession();");
			 daoImpl.println();
			 daoImpl.println("               try{");
			 daoImpl.println("              	List<"+className+"> result = session.selectList(\""+domainPath.replaceAll("/", ".")+"."+className+"\", TABLE_NAME,  "+indicatorVariable+".getObject(),"+classVariable+"Condition ,bounds);");
			 daoImpl.println("                    return result;");	
			 daoImpl.println();	
			 daoImpl.println("                }");
			 daoImpl.println("                finally{");
			 daoImpl.println("              	session.closeDbSession();");
			 daoImpl.println("              }");
			 
			 daoImpl.println("         }");
			  
			 daoImpl.println("}");
			 daoImpl.close();
			 
			
		}
	
	
}
